<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  

  
  <title>Android——PorterDuffXfermode | 海晨忆的博客</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  
  
  
  <meta name="description" content="简介&amp;emsp;&amp;emsp;PorterDuffXfermode是什么鬼？个人理解，简单的来讲就是做两个Bitmap操作的，什么操作呢？有裁剪，合并等等，有16种图形混合模式。先举一个简单的例子，我们在慢慢讲：">
<meta property="og:type" content="article">
<meta property="og:title" content="Android——PorterDuffXfermode">
<meta property="og:url" content="https://haichenyi.com/2018/05/13/Android——PorterDuffXfermode/index.html">
<meta property="og:site_name" content="海晨忆的博客">
<meta property="og:description" content="简介&amp;emsp;&amp;emsp;PorterDuffXfermode是什么鬼？个人理解，简单的来讲就是做两个Bitmap操作的，什么操作呢？有裁剪，合并等等，有16种图形混合模式。先举一个简单的例子，我们在慢慢讲：">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="https://haichenyi.com/uploads/article/2018-05-13/简介demo图.png">
<meta property="og:image" content="https://haichenyi.com/uploads/article/2018-05-13/注意点1.png">
<meta property="og:image" content="https://haichenyi.com/uploads/article/2018-05-13/注意点2.png">
<meta property="og:image" content="https://haichenyi.com/uploads/article/2018-05-13/注意点3.png">
<meta property="og:image" content="https://haichenyi.com/uploads/article/2018-05-13/去掉saveLayer(">
<meta property="og:image" content="https://haichenyi.com/uploads/article/2018-05-13/saveLayer.png">
<meta property="og:image" content="https://haichenyi.com/uploads/article/2018-05-13/no_saveLayer.png">
<meta property="og:image" content="https://haichenyi.com/uploads/article/2018-05-13/DST.png">
<meta property="og:image" content="https://haichenyi.com/uploads/article/2018-05-13/SRC_OVER.png">
<meta property="og:image" content="https://haichenyi.com/uploads/article/2018-05-13/DST_OVER.png">
<meta property="og:image" content="https://haichenyi.com/uploads/article/2018-05-13/SRC_IN.png">
<meta property="og:image" content="https://haichenyi.com/uploads/article/2018-05-13/DST_IN.png">
<meta property="og:image" content="https://haichenyi.com/uploads/article/2018-05-13/SRC_OUT.png">
<meta property="og:image" content="https://haichenyi.com/uploads/article/2018-05-13/DST_OUT.png">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/7041675-dcdb3859d8e4fbf8.gif?imageMogr2/auto-orient/strip">
<meta property="og:image" content="https://upload-images.jianshu.io/upload_images/7041675-946eca2d7f94cdcf.gif?imageMogr2/auto-orient/strip">
<meta property="og:updated_time" content="2019-09-18T08:51:58.242Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Android——PorterDuffXfermode">
<meta name="twitter:description" content="简介&amp;emsp;&amp;emsp;PorterDuffXfermode是什么鬼？个人理解，简单的来讲就是做两个Bitmap操作的，什么操作呢？有裁剪，合并等等，有16种图形混合模式。先举一个简单的例子，我们在慢慢讲：">
<meta name="twitter:image" content="https://haichenyi.com/uploads/article/2018-05-13/简介demo图.png">
  
    <link rel="alternate" href="/atom.xml" title="海晨忆的博客" type="application/atom+xml">
  
  
    <link rel="icon" href="/uploads/artistic_image/head.jpg">
  
  
    <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  
  <link rel="stylesheet" href="/css/style.css">
  <link rel="stylesheet" href="/css/highlight.css">
  <script>
  let antiquityStorage = window.sessionStorage.getItem('antiquitySessionStorage');
  if (antiquityStorage == '' || antiquityStorage == null) {
    var antiquityLoader = '<div id="loaderbox"><div class="loader"><div class="load-roll"><div class="load-top"></div><div class="load-right"></div><div class="load-bottom"></div></div></div></div>';
    document.write(antiquityLoader);
    document.body.style.overflow = 'hidden'
  }
  </script>
</head>

<body>
  <div id="fullpage" class="mobile-nav-right">
    
      <div id="wrapper" style="background-image: url(/uploads/artistic_image/bg.jpg)" title="背景图片来自网络">
    
    
      <header id="header">
  <div id="nav-toggle" class="nav-toggle"></div>
  <div class="head-box global-width">
    <nav class="nav-box nav-right">
      
        <a class="nav-item" href="/" title
        
        >首页</a>
      
        <a class="nav-item" href="/archives" title
        
        >归档</a>
      
        <a class="nav-item" href="/about" title
        
        >简历</a>
      
    </nav>
  </div>
</header>
      <div id="middlecontent" title class="global-width sidebar-left">
        <section id="main"><article id="post-Android——PorterDuffXfermode" class="article global-container article-type-post" itemscope itemprop="blogPost">
  
    <header class="article-header">
      
  
    <h1 class="article-title" itemprop="name">
      Android——PorterDuffXfermode
    </h1>
  

    </header>
  
  <div class="article-meta">
    <a href="/2018/05/13/Android——PorterDuffXfermode/" class="article-date">
  <time datetime="2018-05-13T14:27:36.000Z" itemprop="datePublished">2018-05-13</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/Android-自定义view/">Android -自定义view</a>
  </div>

    
  </div>
  
    <span id="busuanzi_container_page_pv">
      本文总阅读量<span id="busuanzi_value_page_pv"></span>次
    </span>
  

  <div class="article-inner">
    
    <div class="article-content article-content-cloud doorframe mac" itemprop="articleBody">
      
        <h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>&emsp;&emsp;PorterDuffXfermode是什么鬼？个人理解，简单的来讲就是做两个Bitmap操作的，什么操作呢？有裁剪，合并等等，有16种图形混合模式。先举一个简单的例子，我们在慢慢讲：</p>
 <a id="more"></a>
<div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line"> * Author: 海晨忆</span><br><span class="line"> * Date: 2018/3/28</span><br><span class="line"> * Desc:</span><br><span class="line"> */</span><br><span class="line">public class MyCustomView extends View &#123;</span><br><span class="line">  private int width = 300;</span><br><span class="line">  private int height = 300;</span><br><span class="line">  private Bitmap dstBmp;</span><br><span class="line">  private Bitmap srcBmp;</span><br><span class="line">  private Paint mPaint;</span><br><span class="line"></span><br><span class="line">  public MyCustomView(Context context) &#123;</span><br><span class="line">    this(context, null);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  public MyCustomView(Context context, @Nullable AttributeSet attrs) &#123;</span><br><span class="line">    this(context, attrs, 0);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  public MyCustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) &#123;</span><br><span class="line">    super(context, attrs, defStyleAttr);</span><br><span class="line">    initView();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  private void initView() &#123;</span><br><span class="line">    setLayerType(View.LAYER_TYPE_SOFTWARE, null);</span><br><span class="line">    srcBmp = makeSrc(width, height);</span><br><span class="line">    dstBmp = makeDst(width, height);</span><br><span class="line">    mPaint = new Paint();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  @Override</span><br><span class="line">  protected void onDraw(Canvas canvas) &#123;</span><br><span class="line">    super.onDraw(canvas);</span><br><span class="line">    canvas.translate(getWidth() / 2 - width / 2, getHeight() / 2 - height / 2);</span><br><span class="line">    canvas.drawColor(Color.BLUE);</span><br><span class="line">    int layerID = canvas.saveLayer(0, 0, width * 2, height * 2, mPaint, Canvas.ALL_SAVE_FLAG);</span><br><span class="line">    canvas.drawBitmap(dstBmp, 0, 0, mPaint);</span><br><span class="line">    @SuppressLint(&quot;DrawAllocation&quot;) PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);</span><br><span class="line">    mPaint.setXfermode(xfermode);</span><br><span class="line">    canvas.drawBitmap(srcBmp, width / 2, height / 2, mPaint);</span><br><span class="line">    mPaint.setXfermode(null);</span><br><span class="line">    canvas.restoreToCount(layerID);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  private Bitmap makeDst(int w, int h) &#123;</span><br><span class="line">    Bitmap dst = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);</span><br><span class="line">    Canvas mCanvas = new Canvas(dst);</span><br><span class="line">    Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);</span><br><span class="line">    mPaint.setColor(Color.RED);</span><br><span class="line">    mCanvas.drawOval(new RectF(0, 0, w, h), mPaint);</span><br><span class="line">    return dst;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  private Bitmap makeSrc(int w, int h) &#123;</span><br><span class="line">    Bitmap src = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);</span><br><span class="line">    Canvas mCanvas = new Canvas(src);</span><br><span class="line">    Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);</span><br><span class="line">    mPaint.setColor(Color.YELLOW);</span><br><span class="line">    mCanvas.drawRect(0, 0, w, h, mPaint);</span><br><span class="line">    return src;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
<p>效果图如下：<br><img src="/uploads/article/2018-05-13/简介demo图.png" alt="简介demo图.png"></p>
<p>&emsp;&emsp;上面画了一个圆形bitmap，画了一个矩形bitmap，设置了一个模式 <strong><em>PorterDuff.Mode.SRC_IN</em></strong> 就变成了上面的形状，这是怎么做到的呢？带着我们的问题，进入我们的主题。</p>
<h2 id="注意点"><a href="#注意点" class="headerlink" title="注意点"></a><strong><em>注意点</em></strong></h2><p>&emsp;&emsp;为什么我要拿一个大标题来写这个呢？因为，我当时卡在这里很久，然后踩着巨人的肩膀，我才踏过去的。</p>
<ol>
<li><p>首先，两个图形必须都是Bitmap，直接用Canvas画形状，做操作，是达不到效果的。重要的事情说三遍：<strong><em>两个图形必须都是Bitmap。两个图形必须都是Bitmap。两个图形必须都是Bitmap</em></strong></p>
</li>
<li><p>其次，避免不必要的麻烦，请先关闭硬件加速。重要的事情说三遍：<strong><em>请先关闭硬件加速。请先关闭硬件加速。请先关闭硬件加速</em></strong></p>
</li>
<li><p>然后，两个bitmap的大小最好一样。</p>
</li>
<li><p>最后，我要强调的是：<strong><em>先绘制的是目标图，后绘制的是源图。</em></strong></p>
</li>
</ol>
<p>&emsp;&emsp;这里一直说bitmap，辣么，怎么生成这个bitmap，生成这个bitmap之后怎么画图形呢？如下代码：</p>
<div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">//第一步，我们先创建一个bitmap对象</span><br><span class="line">Bitmap dst = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);</span><br><span class="line">//第二步，我们通过这个bitmap对象创建一个画布，</span><br><span class="line">//说白了，就是new 一个画布，把bitmap放到画布的构造方法里面</span><br><span class="line">    Canvas mCanvas = new Canvas(dst);</span><br><span class="line">    Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);</span><br><span class="line">    mPaint.setColor(Color.RED);</span><br><span class="line">//最后，在这个画布上面的所有操作，最后都是呈现在bitmap上面。</span><br><span class="line">//就像这里的，在这个画布上面画了一个椭圆，其实，最后我们的bitmap就是一个椭圆</span><br><span class="line">    mCanvas.drawOval(new RectF(0, 0, w, h), mPaint);</span><br></pre></td></tr></table></figure></div>
<p>&emsp;&emsp;可以，bitmap会创建了，再就是我们前面说的两个bitmap，<strong><em>先绘制的是目标图，后绘制的是源图</em></strong>，一个是dst（目标图片，下层，先画），一个是src（源图片，上层，后画）。就是我们上面的自定view里面的onDraw()方法里面，用onDraw的canvas画的东西。</p>
<p>&emsp;&emsp;我们如果不用这个xfermode模式，我们的代码应该是这样的：</p>
<div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">@Override</span><br><span class="line">  protected void onDraw(Canvas canvas) &#123;</span><br><span class="line">    super.onDraw(canvas);</span><br><span class="line">    canvas.translate(getWidth() / 2 - width / 2, getHeight() / 2 - height / 2);</span><br><span class="line">    canvas.drawColor(Color.BLUE);</span><br><span class="line">    canvas.drawBitmap(dstBmp, 0, 0, mPaint);</span><br><span class="line">    canvas.drawBitmap(srcBmp, width / 2, height / 2, mPaint);</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure></div>
<p>&emsp;&emsp;很简单的几行代码，把画布移到正中间，给画布加一个背景蓝色，先画dst，后画src，跑出来的效果图应该是下面这样的：</p>
<p><img src="/uploads/article/2018-05-13/注意点1.png" alt="注意点1.png"></p>
<p>&emsp;&emsp;我们如果加上这个xfermode模式里面的 <strong><em>PorterDuff.Mode.SRC_IN</em></strong>模式，代码如下：</p>
<div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">@Override</span><br><span class="line">  protected void onDraw(Canvas canvas) &#123;</span><br><span class="line">    super.onDraw(canvas);</span><br><span class="line">    canvas.translate(getWidth() / 2 - width / 2, getHeight() / 2 - height / 2);</span><br><span class="line">    canvas.drawColor(Color.BLUE);</span><br><span class="line">    int layerID = canvas.saveLayer(0, 0, width * 2, height * 2, mPaint, Canvas.ALL_SAVE_FLAG);</span><br><span class="line">    canvas.drawBitmap(dstBmp, 0, 0, mPaint);</span><br><span class="line">    @SuppressLint(&quot;DrawAllocation&quot;) PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);</span><br><span class="line">    mPaint.setXfermode(xfermode);</span><br><span class="line">    canvas.drawBitmap(srcBmp, width / 2, height / 2, mPaint);</span><br><span class="line">    mPaint.setXfermode(null);</span><br><span class="line">    canvas.restoreToCount(layerID);</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure></div>
<p>&emsp;&emsp;比上面的代码，就多加了一个xfermode模式，他们要是同一个画笔，用完之后，记得要把这个模式置null这个saveLayer等会讲，先不说。跑出来的效果图，如下：</p>
<p><img src="/uploads/article/2018-05-13/注意点2.png" alt="注意点2.png"></p>
<p>&emsp;&emsp;前面，我们一直都在强调dst先画，src后画，如果调换一下，会是什么样的结果呢？代码我就不贴出来了，就把那两个drawBitmap调换一个位置，跑出来的效果图，如下：</p>
<p><img src="/uploads/article/2018-05-13/注意点3.png" alt="注意点3.png"></p>
<p>&emsp;&emsp;很明显，跟我们的预期结果不一样。这是为什么呢？带着我们的问题进入下一节。</p>
<h2 id="十六种模式和saveLayer"><a href="#十六种模式和saveLayer" class="headerlink" title="十六种模式和saveLayer()"></a>十六种模式和saveLayer()</h2><h3 id="十六种模式"><a href="#十六种模式" class="headerlink" title="十六种模式"></a>十六种模式</h3><table>
<thead>
<tr>
<th style="text-align:center">名字</th>
<th style="text-align:center">含义</th>
<th style="text-align:center">名字</th>
<th style="text-align:center">含义</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">CLEAR</td>
<td style="text-align:center">清除模式［0，0］，即最终所有点的像素的alpha 和color 都为 0，所以画出来的效果只有白色背景</td>
<td style="text-align:center">SRC</td>
<td style="text-align:center">显示上层绘制图片</td>
</tr>
<tr>
<td style="text-align:center">DST</td>
<td style="text-align:center">显示下层绘制图片</td>
<td style="text-align:center">SRC_OVER</td>
<td style="text-align:center">正常绘制显示，上下层绘制叠盖</td>
</tr>
<tr>
<td style="text-align:center">DST_OVER</td>
<td style="text-align:center">上下层都显示，下层居上显示</td>
<td style="text-align:center">SRC_IN</td>
<td style="text-align:center">取两层绘制交集。显示上层</td>
</tr>
<tr>
<td style="text-align:center">DST_IN</td>
<td style="text-align:center">取两层绘制交集，显示下层</td>
<td style="text-align:center">SRC_OUT</td>
<td style="text-align:center">取上层绘制非交集部分</td>
</tr>
<tr>
<td style="text-align:center">DST_OUT</td>
<td style="text-align:center">取下层绘制非交集部分</td>
<td style="text-align:center">SRC_ATOP</td>
<td style="text-align:center">取下层非交集部分与上层交集部分</td>
</tr>
<tr>
<td style="text-align:center">DST_ATOP</td>
<td style="text-align:center">取上层非交集部分与下层交集部分</td>
<td style="text-align:center">XOR</td>
<td style="text-align:center">异或：去除两图层交集部分</td>
</tr>
<tr>
<td style="text-align:center">DARKEN</td>
<td style="text-align:center">取两图层全部区域，交集部分颜色加深</td>
<td style="text-align:center">LIGHTEN</td>
<td style="text-align:center">取两图层全部，点亮交集部分颜色</td>
</tr>
<tr>
<td style="text-align:center">MULTIPLY</td>
<td style="text-align:center">取两图层交集部分叠加后颜色</td>
<td style="text-align:center">SCREEN</td>
<td style="text-align:center">取两图层全部区域，交集部分变为透明色</td>
</tr>
</tbody>
</table>
<p>PS：名称前面都应该有：<strong><em>PorterDuff.Mode</em></strong> ，例如：PorterDuff.Mode.CLEAR</p>
<p>&emsp;&emsp;什么？有的看不懂什么意思？没关系，我也没指望你一次就看懂，我们先来说一说saveLayer()，且听我娓娓道来。</p>
<h3 id="saveLayer"><a href="#saveLayer" class="headerlink" title="saveLayer()"></a>saveLayer()</h3><p>&emsp;&emsp;这个方法是干嘛用的？保存指定区域内画布的内容。</p>
<div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">public int saveLayer(RectF bounds, Paint paint, int saveFlags)  </span><br><span class="line">public int saveLayer(float left, float top, float right, float bottom,Paint paint, int saveFlags)</span><br></pre></td></tr></table></figure></div>
<p>&emsp;&emsp;后面的saveFlags，有6个值，我们这里用到的 <strong><em>Canvas.ALL_SAVE_FLAG</em></strong>，很明显，表示保存所有内容。我们这里如果把这个方法去掉，会是什么样的结果呢？代码就不贴出来了，就直接注释掉saveLayer的两行代码。还是先画dst，后画src，跑出来的效果图如下：</p>
<p><img src="/uploads/article/2018-05-13/去掉saveLayer(" alt="去掉saveLayer().png">.png)</p>
<p>我们先规定两点：</p>
<ol>
<li>先画dst，也就是目标图像，是一个圆形。</li>
<li>后画src，也就是源图像，是一个矩形。</li>
</ol>
<table>
<thead>
<tr>
<th style="text-align:center">代码名称1</th>
<th style="text-align:center">顺序</th>
<th style="text-align:center">中文名称</th>
<th style="text-align:center">形状</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">dst</td>
<td style="text-align:center">先画</td>
<td style="text-align:center">目标图像</td>
<td style="text-align:center">红色圆形</td>
</tr>
<tr>
<td style="text-align:center">src</td>
<td style="text-align:center">后画</td>
<td style="text-align:center">源图像</td>
<td style="text-align:center">黄色矩形</td>
</tr>
</tbody>
</table>
<p>&emsp;&emsp;规定好之后，我们再来说一说这个 <strong><em>SRC_IN</em></strong>，我们前面说了：取两层绘制交集。显示上层。首先IN是取交集部分，OUT是取非交集部分。这个就是说最后显示的图形，他们的交集部分，显示src，也就是矩形的颜色，也就是黄色。先画的dst，他自然在src的上层。所以，显示dst的形状，两者交集部分显示src的颜色。可以看下图：</p>
<p><img src="/uploads/article/2018-05-13/saveLayer.png" alt="saveLayer.png"></p>
<p>&emsp;&emsp;我们再来说说saveLayer的绘制流程：如上图所示，它会创建一个全新图名的bitmap，大小跟你前面指定的保存区域相同，然后，绘制的图形会保存在这个全新透明的bitmap上面，最后把这个透明的bitmap画在画布上面。</p>
<p>&emsp;&emsp;辣么，没有savelayer()方法的绘制流程呢？如下图：</p>
<p><img src="/uploads/article/2018-05-13/no_saveLayer.png" alt="no_saveLayer.png"></p>
<p>他是直接作用在画布上面的。</p>
<h2 id="常用的PorterDuffXfermode模式介绍"><a href="#常用的PorterDuffXfermode模式介绍" class="headerlink" title="常用的PorterDuffXfermode模式介绍"></a>常用的PorterDuffXfermode模式介绍</h2><h3 id="SRC模式"><a href="#SRC模式" class="headerlink" title="SRC模式"></a>SRC模式</h3><p>&emsp;&emsp;只保留源图像的 alpha 和 color ，所以绘制出来只有源图，有时候会感觉分不清先绘制的是源图还是后绘制的是源图，这个时候可以这么记，先绘制的是目标图，不管任何时候，一定要做一个有目标的人，目标在前！（未达到我们的预期效果，感觉有问题）</p>
<h3 id="DST模式"><a href="#DST模式" class="headerlink" title="DST模式"></a>DST模式</h3><p>&emsp;&emsp;只显示目标图片，也就是只显示红色的圆形。</p>
<p><img src="/uploads/article/2018-05-13/DST.png" alt="DST.png"></p>
<h3 id="SRC-OVER模式"><a href="#SRC-OVER模式" class="headerlink" title="SRC_OVER模式"></a>SRC_OVER模式</h3><p>&emsp;&emsp;在目标图片顶部绘制源图像,从命名上也可以看出来就是把源图像绘制在上方，也就是把黄色长方形，画在红色圆形的上面。效果图如下：</p>
<p><img src="/uploads/article/2018-05-13/SRC_OVER.png" alt="SRC_OVER.png"></p>
<h3 id="DST-OVER模式"><a href="#DST-OVER模式" class="headerlink" title="DST_OVER模式"></a>DST_OVER模式</h3><p>&emsp;&emsp;把目标图像绘制在上方。与前一个相反，把红色圆形画在长方形上面。效果图如下：</p>
<p><img src="/uploads/article/2018-05-13/DST_OVER.png" alt="DST_OVER.png"></p>
<h3 id="SRC-IN模式"><a href="#SRC-IN模式" class="headerlink" title="SRC_IN模式"></a>SRC_IN模式</h3><p>&emsp;&emsp;在两者相交的地方绘制源图像，并且绘制的效果会受到目标图像对应地方透明度的影响。</p>
<p>&emsp;&emsp;有点绕，我分成几段讲出来：</p>
<p>&emsp;&emsp;也就是说，两者相交的位置，显示源图像，也就是黄色的矩形，目标图像的透明度为0，然后，&emsp;源图像的其他位置的透明度&emsp;&emsp;会跟源图像与目标图像相交的地方&emsp;&emsp;的目标图像的透明度一样。</p>
<p>&emsp;&emsp;有点绕。其实，就是说源图像的其他地方隐藏，就显示相交的位置。效果图如下：</p>
<p><img src="/uploads/article/2018-05-13/SRC_IN.png" alt="SRC_IN.png"></p>
<h3 id="DST-IN模式"><a href="#DST-IN模式" class="headerlink" title="DST_IN模式"></a>DST_IN模式</h3><p>&emsp;&emsp;跟前面刚好对应，在两者相交的地方绘制目标图像，并且，绘制效果会受到源图像对应地方透明度的影响。我们最是绘制目标图像。效果图如下：</p>
<p><img src="/uploads/article/2018-05-13/DST_IN.png" alt="DST_IN.png"></p>
<h3 id="SRC-OUT模式"><a href="#SRC-OUT模式" class="headerlink" title="SRC_OUT模式"></a>SRC_OUT模式</h3><p>&emsp;&emsp;在不相交的地方绘制源图像，相交处根据目标alpha进行过滤，目标色完全不透明时则完全过滤，完全透明则不过滤；</p>
<p><img src="/uploads/article/2018-05-13/SRC_OUT.png" alt="SRC_OUT.png"></p>
<h3 id="DST-OUT模式"><a href="#DST-OUT模式" class="headerlink" title="DST_OUT模式"></a>DST_OUT模式</h3><p>&emsp;&emsp;同样，可以类比SRC_OUT , 在不相交的地方绘制目标图像，相交处根据源图像alpha进行过滤，完全不透明处则完全过滤，完全透明则不过滤；</p>
<p><img src="/uploads/article/2018-05-13/DST_OUT.png" alt="DST_OUT.png"></p>
<p>太多了，后面就不写了，用的也比较少。</p>
<p>用途，加上上一篇的贝赛尔曲线的水波纹。很明显，我就想做如下效果：</p>
<p><img src="https://upload-images.jianshu.io/upload_images/7041675-dcdb3859d8e4fbf8.gif?imageMogr2/auto-orient/strip" alt="圆形水波纹.gif"></p>
<p>这个圆只是一种，这只是一个demo，这个圆，你可以换成任意的形状。你知道水波纹用贝赛尔曲线怎么做，知道了，PorterDuffXfermode这个模式，两张图片是怎么切割。像这样的，还不就是一个道理。随手拈来。如下图：</p>
<p><img src="https://upload-images.jianshu.io/upload_images/7041675-946eca2d7f94cdcf.gif?imageMogr2/auto-orient/strip" alt="自定义背景.gif"></p>
<p>这个水波纹的，已经全部封装好了。任意改变背景图片。<a href="https://download.csdn.net/download/qq_27634797/10314335" target="_blank" rel="noopener">项目链接</a></p>

      
    </div>
    
      <footer class="article-footer">
        完
      </footer>
    
  </div>
  
    
<nav id="article-nav">
  <div class="article-nav-block">
    
      <a href="/2018/05/13/Android转场动画——共享元素/" id="article-nav-newer" class="article-nav-link-wrap">
        <strong class="article-nav-caption"></strong>
        <div class="article-nav-title">
          
            Android转场动画——共享元素
          
        </div>
      </a>
    
  </div>
  <div class="article-nav-block">
    
      <a href="/2018/05/13/Android自定义View——贝赛尔曲线/" id="article-nav-older" class="article-nav-link-wrap">
        <div class="article-nav-title">Android自定义View——贝赛尔曲线</div>
        <strong class="article-nav-caption"></strong>
      </a>
    
  </div>
</nav>

    
  
  
</article>
</section>
        <aside id="sidebar">
  
    <div class="widget-box">
  <div class="avatar-box avatar-item">
    <img class="avatar" src="/uploads/artistic_image/head.jpg" title="头像来自网络"></img>
    <h3 class="avatar-name">
      
        海晨忆
      
    </h3>
    <p class="avatar-slogan">
      先谋生，再谋爱。人间值得，未来可期。
    </p>
  </div>
</div>


  
    
  <div class="widget-box">
    <h3 class="widget-title">分类</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/Android-Socket/">Android -Socket</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-加密算法/">Android -加密算法</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-常用功能/">Android -常用功能</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-框架/">Android -框架</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-源码解析/">Android -源码解析</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-自定义view/">Android -自定义view</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-设计模式/">Android -设计模式</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/JAVA-并发/">JAVA -并发</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Java-SpringBoot/">Java -SpringBoot</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Tomcat/">Tomcat</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/kotlin/">kotlin</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/数据库-JDBC/">数据库 -JDBC</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/数据库-MySQL/">数据库 -MySQL</a></li></ul>
    </div>
  </div>


  
    

  
    
  
    
  <div class="widget-box">
    <h3 class="widget-title">归档</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/07/">July 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/11/">November 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/10/">October 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/09/">September 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/08/">August 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/07/">July 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/06/">June 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/10/">October 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/05/">May 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/03/">March 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/02/">February 2018</a></li></ul>
    </div>
  </div>

  
    
  <div class="widget-box">
    <h3 class="widget-title">最新文章</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2021/07/27/JAVA—公平锁，非公平锁，悲观锁，乐观锁，死锁/">JAVA—公平锁，非公平锁，悲观锁，乐观锁，死锁</a>
          </li>
        
          <li>
            <a href="/2021/07/19/JAVA—线程同步器AQS/">JAVA—线程同步器AQS</a>
          </li>
        
          <li>
            <a href="/2021/07/07/Android模拟点击/">Android模拟点击</a>
          </li>
        
          <li>
            <a href="/2019/11/27/SpringBoot系列-消息-RabbitMQ-（二十）/">SpringBoot系列-消息(RabbitMQ)（二十）</a>
          </li>
        
          <li>
            <a href="/2019/11/13/SpringBoot系列-Docker（十九）/">SpringBoot系列-Docker（十九）</a>
          </li>
        
      </ul>
    </div>
  </div>

  
      <div class="widget-box">
    <h3 class="widget-title">友情链接</h3>
    <div class="widget">
      
        <a class="hrf" style="display: block;" href="https://github.com/haichenyi" title target='_blank'
        >Github</a>
      
        <a class="hrf" style="display: block;" href="https://www.jianshu.com/u/6077ee440c37" title target='_blank'
        >简书</a>
      
        <a class="hrf" style="display: block;" href="https://blog.csdn.net/qq_27634797" title target='_blank'
        >CSDN</a>
      
    </div>
  </div>

  
</aside>
      </div>
      <footer id="footer">
  <div class="foot-box footers global-width">
    &copy;2017-2021 海晨忆 &nbsp;&nbsp;
    <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span id="busuanzi_container_site_pv">阁下是第<span id="busuanzi_value_site_pv"></span>个访客</span>
  </div>
</footer>
      <script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<script>
if (!window.jQuery) {
var script = document.createElement('script');
script.src = "/js/jquery-2.0.3.min.js";
document.body.write(script);
}
</script>

  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css">
  <script src="/fancybox/jquery.fancybox.pack.js"></script>


<script src="/js/script.js"></script>



    </div>
    <nav id="mobile-nav" class="mobile-nav-box">
  <div class="mobile-nav-img mobile-nav-top"></div>
  
    <a href="/" class="mobile-nav-link">首页</a>
  
    <a href="/archives" class="mobile-nav-link">归档</a>
  
    <a href="/about" class="mobile-nav-link">简历</a>
  
  <div class="mobile-nav-img  mobile-nav-bottom"></div>
</nav>    
  </div>
</body>
</html>